"""
某发信机调谐电容器温度监测微系统

本系统用于监测12列×5行的调谐电容器温度状态，并提供健康指数和任务指数管理功能。

## 系统布局
- 主界面：显示电容器状态、健康指数、任务指数和接入状态
- 参数设置：配置系统参数

## 健康指数计算规则

### 基本计算公式
健康指数 = 125 - 该列5个电容的平均温度

### 特殊情况处理
- 如果该列中任何一个电容温度 ≥ 75°C，则该列健康指数会降低：
  健康指数 = (125 - 该列平均温度) × 0.6

### 计算逻辑
- 每列有5个电容（C1x, C2x, C3x, C4x, C5x）
- 计算该列5个电容温度的平均值
- 健康指数 = 125 - 平均温度
- 温度越低，健康指数越高
- 如果有电容温度过高（≥75°C），健康指数会打6折

## 任务指数计算规则

### 基本规则
- 任务指数上限为100次
- 当某列被选中参与工作时，任务指数+1
- 如果任务指数 > 100，该列不可用

### 任务指数增加逻辑
- 根据选择的频点（F1需要3列，F2需要4列，F3需要5列）
- 系统会按健康指数和任务裕度的加权排序选择最优的列
- 被选中的列的任务指数会自动+1

## 加权选择算法

### 选择依据
A = 0.7 × 健康指数 + 0.3 × 任务裕度

其中：
- 任务裕度 = 100 - 当前任务指数
- 健康指数权重：70%
- 任务裕度权重：30%

## 温度阈值

- **≥75°C**：红色，不可用
- **62.5-75°C**：黄色，堪用
- **50-62.5°C**：黄色，堪用
- **<50°C**：绿色，可用

## 频点配置

- **F1（3列）**：需要3列电容器参与工作
- **F2（4列）**：需要4列电容器参与工作
- **F3（5列）**：需要5列电容器参与工作

## 系统功能

1. 实时监测60个电容器的温度状态
2. 自动计算每列的健康指数和任务指数
3. 根据健康指数和任务裕度智能选择最优电容器列
4. 可视化显示电容器状态、健康指数、任务指数和接入状态
5. 支持不同频点的工作模式配置
"""

"""
调谐电容器温度监测微系统
作者：于爽
日期：2025.7.19
"""

import tkinter as tk
from tkinter import ttk
import math
import json
import os
import serial.tools.list_ports
import serial
import threading
import time
from tkinter import messagebox

class CapacitorMonitorGUI:
    """
    调谐电容器温度监测微系统GUI类
    作者：于爽
    日期：2025.7.19
    """
    def __init__(self, root):
        self.root = root
        self.root.title("某发信机调谐电容器温度监测微系统")
        self.root.geometry("1400x900")
        
        # 设置窗口图标和样式
        self.root.configure(bg='#f0f0f0')
        
        # 启动时最大化窗口
        self.root.state('zoomed')
        
        # 串口连接状态
        self.serial_connected = False
        self.serial_port = None
        
        # 温度数据
        self.temperatures = [[45.2 for _ in range(5)] for _ in range(12)]  # 12列5行的温度数据
        
        # 串口接收线程
        self.receive_thread = None
        self.stop_receive = False
        
        # 配置文件路径
        self.config_file = "serial_config.json"
        
        # 加载保存的串口设置
        self.load_serial_config()
        
        # 配置主窗口的网格权重
        self.root.grid_rowconfigure(0, weight=0)  # 标题行
        self.root.grid_rowconfigure(1, weight=1)  # 主内容区域
        self.root.grid_columnconfigure(0, weight=1)
        
        # 创建标题
        self.create_title()
        
        # 创建主内容区域
        self.create_main_content()
        
        # 绑定窗口大小变化事件
        self.root.bind('<Configure>', self.on_window_resize)
        
        # 初始化健康指数
        self.root.after(100, self.update_all_health_indices)
        # 启动时禁用频点下拉菜单
        self.freq_combobox.config(state='disabled')
    
    def on_window_resize(self, event):
        """窗口大小变化时的处理"""
        if event.widget == self.root:
            # 重新计算字体大小和控件尺寸
            self.update_layout()
    
    def update_layout(self):
        """根据窗口大小更新布局"""
        # 获取当前窗口大小
        window_width = self.root.winfo_width()
        window_height = self.root.winfo_height()
        
        # 根据窗口大小调整字体
        if window_width < 1200:
            title_font_size = 14
            main_font_size = 10
            small_font_size = 8
        elif window_width < 1600:
            title_font_size = 16
            main_font_size = 11
            small_font_size = 9
        else:
            title_font_size = 18
            main_font_size = 12
            small_font_size = 10
        
        # 更新标题字体
        if hasattr(self, 'title_label'):
            self.title_label.config(font=('Microsoft YaHei', title_font_size, 'bold'))
        
        # 更新电容器阵列字体
        if hasattr(self, 'capacitor_widgets'):
            for col in range(12):
                for row in range(5):
                    if self.capacitor_widgets[col][row]:
                        widget = self.capacitor_widgets[col][row]
                        if 'name_label' in widget:
                            widget['name_label'].config(font=('Microsoft YaHei', small_font_size))
                        if 'temp_label' in widget:
                            widget['temp_label'].config(font=('Microsoft YaHei', small_font_size))
        
    def create_title(self):
        """创建标题"""
        title_frame = tk.Frame(self.root, bg='#2c3e50', height=60)
        title_frame.grid(row=0, column=0, sticky='ew')
        title_frame.grid_propagate(False)
        
        self.title_label = tk.Label(
            title_frame, 
            text="某发信机调谐电容器温度监测微系统",
            font=('Microsoft YaHei', 18, 'bold'),
            fg='white',
            bg='#2c3e50'
        )
        self.title_label.pack(expand=True)
        
    def create_main_content(self):
        """创建主内容区域"""
        # 创建主内容框架
        main_frame = tk.Frame(self.root, bg='#f8f9fa')
        main_frame.grid(row=1, column=0, sticky='nsew', padx=10, pady=10)
        
        # 配置主框架的网格权重
        main_frame.grid_rowconfigure(0, weight=0)  # 控制面板
        main_frame.grid_rowconfigure(1, weight=0)  # 分隔线
        main_frame.grid_rowconfigure(2, weight=1)  # 电容器显示区域
        main_frame.grid_columnconfigure(0, weight=1)
        
        # 创建控制面板
        self.create_control_panel(main_frame)
        
        # 创建分隔线
        separator = ttk.Separator(main_frame, orient='horizontal')
        separator.grid(row=1, column=0, sticky='ew', pady=10)
        
        # 创建电容器显示区域
        self.create_capacitor_display_area(main_frame)
        
    def create_control_panel(self, parent):
        """创建控制面板"""
        control_frame = tk.Frame(parent, bg='#f8f9fa')
        control_frame.grid(row=0, column=0, sticky='ew', pady=5)
        
        # 配置控制面板的列权重
        control_frame.grid_columnconfigure(0, weight=0)  # 串口设置
        control_frame.grid_columnconfigure(1, weight=0)  # 分隔
        control_frame.grid_columnconfigure(2, weight=0)  # 频点设置
        control_frame.grid_columnconfigure(3, weight=1)  # 空白区域
        
        # 串口设置区域
        serial_frame = tk.LabelFrame(control_frame, text="串口设置", bg='#f8f9fa', font=('Microsoft YaHei', 10))
        serial_frame.grid(row=0, column=0, sticky='ew', padx=(0, 10))
        
        # 串口选择
        tk.Label(serial_frame, text="串口:", font=('Microsoft YaHei', 9), bg='#f8f9fa').pack(side='left', padx=5, pady=5)
        self.serial_combobox = ttk.Combobox(
            serial_frame,
            values=["COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8"],
            font=('Microsoft YaHei', 9),
            width=8,
            state='readonly'
        )
        self.serial_combobox.pack(side='left', padx=5, pady=5)
        self.serial_combobox.set(self.saved_serial_port)
        
        # 波特率选择
        tk.Label(serial_frame, text="波特率:", font=('Microsoft YaHei', 9), bg='#f8f9fa').pack(side='left', padx=5, pady=5)
        self.baudrate_combobox = ttk.Combobox(
            serial_frame,
            values=["9600", "19200", "38400", "57600", "115200"],
            font=('Microsoft YaHei', 9),
            width=8,
            state='readonly'
        )
        self.baudrate_combobox.pack(side='left', padx=5, pady=5)
        self.baudrate_combobox.set(self.saved_baudrate)
        
        # 刷新按钮
        self.refresh_button = tk.Button(
            serial_frame,
            text="刷新",
            font=('Microsoft YaHei', 9),
            relief='flat',
            command=self.refresh_serial_ports,
            width=8  # 设置固定宽度，与波特率列表一致
        )
        self.refresh_button.pack(side='left', padx=5, pady=5)
        
        # 连接状态指示灯
        self.connection_canvas = tk.Canvas(
            serial_frame,
            width=20,
            height=20,
            bg='#f8f9fa',
            highlightthickness=0
        )
        self.connection_canvas.pack(side='left', padx=5, pady=5)
        self.draw_connection_indicator(False)
        
        # 连接按钮
        self.connect_button = tk.Button(
            serial_frame,
            text="连接",
            font=('Microsoft YaHei', 9),
            relief='flat',
            command=self.toggle_connection,
            width=8  # 设置固定宽度，与波特率列表一致
        )
        self.connect_button.pack(side='left', padx=5, pady=5)
        
        # 初始化串口列表
        self.refresh_serial_ports()
        
        # 频点设置区域
        freq_frame = tk.LabelFrame(control_frame, text="工作频点", bg='#f8f9fa', font=('Microsoft YaHei', 10))
        freq_frame.grid(row=0, column=2, sticky='ew', padx=(10, 0))
        
        self.freq_combobox = ttk.Combobox(
            freq_frame,
            values=["请选择频点", "F1（3列）", "F2（4列）", "F3（5列）"],
            font=('Microsoft YaHei', 10),
            width=15,
            state='readonly'
        )
        self.freq_combobox.pack(side='left', padx=10, pady=5)
        self.freq_combobox.set("请选择频点")
        self.freq_combobox.bind('<<ComboboxSelected>>', self.on_freq_selected)
        
    def create_capacitor_display_area(self, parent):
        """创建电容器显示区域"""
        # 创建可滚动的显示区域
        canvas = tk.Canvas(parent, bg='#f8f9fa', highlightthickness=0)
        scrollbar = ttk.Scrollbar(parent, orient="vertical", command=canvas.yview)
        scrollable_frame = tk.Frame(canvas, bg='#f8f9fa')
        
        scrollable_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )
        
        canvas.create_window((0, 0), window=scrollable_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)
        
        canvas.grid(row=2, column=0, sticky='nsew')
        scrollbar.grid(row=2, column=1, sticky='ns')
        
        # 配置网格权重
        parent.grid_rowconfigure(2, weight=1)
        parent.grid_columnconfigure(0, weight=1)
        
        # 创建电容器显示内容
        self.create_capacitor_content(scrollable_frame)
        
    def create_capacitor_content(self, parent):
        """创建电容器显示内容"""
        # 接发信机标题
        tx_title_label = tk.Label(
            parent,
            text="接发信机",
            font=('Microsoft YaHei', 14, 'bold'),
            bg='#f8f9fa',
            fg='#2c3e50'
        )
        tx_title_label.pack(pady=5)
        
        # 电容器阵列
        self.create_capacitor_array(parent)
        
        # 健康指数
        self.create_health_index(parent)
        
        # 任务指数
        self.create_task_index(parent)
        
        # 接入状态
        self.create_access_controls(parent)
        
        # 接天馈标题
        rx_title_label = tk.Label(
            parent,
            text="接天馈",
            font=('Microsoft YaHei', 14, 'bold'),
            bg='#f8f9fa',
            fg='#2c3e50'
        )
        rx_title_label.pack(pady=5)
        
    def create_capacitor_array(self, parent):
        """创建12*5的电容阵列"""
        # 电容器组配置
        capacitor_groups = [
            ["C15", "C14", "C13", "C12", "C11"],
            ["C25", "C24", "C23", "C22", "C21"],
            ["C35", "C34", "C33", "C32", "C31"],
            ["C45", "C44", "C43", "C42", "C41"],
            ["C55", "C54", "C53", "C52", "C51"],
            ["C65", "C64", "C63", "C62", "C61"],
            ["C75", "C74", "C73", "C72", "C71"],
            ["C85", "C84", "C83", "C82", "C81"],
            ["C95", "C94", "C93", "C92", "C91"],
            ["C105", "C104", "C103", "C102", "C101"],
            ["C115", "C114", "C113", "C112", "C111"],
            ["C125", "C124", "C123", "C122", "C121"]
        ]
        
        # 存储电容控件的引用
        self.capacitor_widgets = [[None for _ in range(5)] for _ in range(12)]
        
        # 创建电容阵列容器
        array_frame = tk.Frame(parent, bg='#f8f9fa')
        array_frame.pack(fill='x', padx=10, pady=5)
        
        # 配置列权重，使所有列均匀分布
        for i in range(12):
            array_frame.grid_columnconfigure(i, weight=1)
        
        # 创建电容阵列
        for row in range(5):  # 5行
            for col in range(12):  # 12列
                capacitor_name = capacitor_groups[col][row]
                
                # 创建电容器标签和状态指示灯
                cell_frame = tk.Frame(array_frame, bg='#f8f9fa', relief='groove', bd=1)
                cell_frame.grid(row=row, column=col, padx=1, pady=1, sticky='ew')
                
                # 配置单元格的权重
                cell_frame.grid_columnconfigure(0, weight=1)
                
                # 电容器名称标签（居中对齐）
                name_label = tk.Label(
                    cell_frame,
                    text=capacitor_name,
                    font=('Microsoft YaHei', 9),
                    bg='#f8f9fa',
                    anchor='center'
                )
                name_label.pack(pady=1, fill='x')
                
                # 圆形状态指示灯（居中对齐）
                status_canvas = tk.Canvas(
                    cell_frame,
                    width=25,
                    height=25,
                    bg='#f8f9fa',
                    highlightthickness=0
                )
                status_canvas.pack(pady=1, anchor='center')
                
                # 绘制圆形指示灯（默认绿色表示正常）
                self.draw_status_indicator(status_canvas, "normal")
                
                # 温度数值显示（精确到一位小数）
                temp_label = tk.Label(
                    cell_frame,
                    text="45.2°C",
                    font=('Microsoft YaHei', 8),
                    bg='#f8f9fa',
                    fg='#2c3e50',
                    anchor='center',
                    width=8,  # 固定宽度为8个字符
                    relief='flat'  # 使用flat样式避免边框变化
                )
                temp_label.pack(pady=1, fill='x')
                
                # 存储控件引用
                self.capacitor_widgets[col][row] = {
                    'status_canvas': status_canvas,
                    'temp_label': temp_label,
                    'name_label': name_label
                }
    
    def create_health_index(self, parent):
        """创建12*1的健康指数"""
        # 健康指数标题
        health_title = tk.Label(
            parent,
            text="健康指数",
            font=('Microsoft YaHei', 12, 'bold'),
            bg='#f8f9fa',
            fg='#2c3e50'
        )
        health_title.pack(pady=2)
        
        # 创建健康指数行
        health_frame = tk.Frame(parent, bg='#f8f9fa')
        health_frame.pack(fill='x', padx=10, pady=2)
        
        # 配置列权重
        for i in range(12):
            health_frame.grid_columnconfigure(i, weight=1)
        
        # 存储健康指数控件的引用
        self.health_widgets = [None for _ in range(12)]
        
        # 创建12个健康指数数值显示
        for col in range(12):
            cell_frame = tk.Frame(health_frame, bg='#f8f9fa', relief='groove', bd=1)
            cell_frame.grid(row=0, column=col, padx=1, pady=1, sticky='ew')
            
            # 健康指数标签
            health_label = tk.Label(
                cell_frame,
                text="H{}".format(col+1),
                font=('Microsoft YaHei', 10),
                bg='#f8f9fa',
                anchor='center'
            )
            health_label.pack(pady=1, fill='x')
            
            # 健康指数数值显示
            health_value = tk.Label(
                cell_frame,
                text="85",
                font=('Microsoft YaHei', 11),
                bg='#ffffff',
                fg='#2c3e50',
                relief='sunken',
                bd=2,
                width=6,
                anchor='center'
            )
            health_value.pack(pady=1)
            
            # 存储健康指数控件引用
            self.health_widgets[col] = health_value
    
    def calculate_health_index(self, col):
        """计算指定列的健康指数"""
        try:
            # 获取该列5个电容的温度
            column_temps = [self.temperatures[col][row] for row in range(5)]
            
            # 计算平均温度
            avg_temp = sum(column_temps) / len(column_temps)
            
            # 检查是否有温度超过75°C
            has_high_temp = any(temp >= 75 for temp in column_temps)
            
            # 计算健康指数
            if has_high_temp:
                # 有高温电容，健康指数降低
                health_index = (125 - avg_temp) * 0.6
            else:
                # 正常情况
                health_index = 125 - avg_temp
            
            # 确保健康指数在合理范围内
            health_index = max(0, min(100, health_index))
            
            return round(health_index, 1)
            
        except Exception as e:
            print("[ERROR] 计算健康指数错误 (列{}): {}".format(col, e))
            return 0.0
    
    def update_health_index(self, col):
        """更新指定列的健康指数显示"""
        try:
            if self.health_widgets and self.health_widgets[col]:
                health_index = self.calculate_health_index(col)
                self.health_widgets[col].config(text="{}".format(health_index))
                
                # 根据健康指数设置颜色
                if health_index >= 80:
                    color = '#28a745'  # 绿色 - 优秀
                elif health_index >= 60:
                    color = '#ffc107'  # 黄色 - 良好
                elif health_index >= 40:
                    color = '#fd7e14'  # 橙色 - 一般
                else:
                    color = '#dc3545'  # 红色 - 差
                
                self.health_widgets[col].config(fg=color)
                
        except Exception as e:
            print("[ERROR] 更新健康指数显示错误 (列{}): {}".format(col, e))
    
    def update_all_health_indices(self):
        """更新所有列的健康指数"""
        for col in range(12):
            self.root.after(0, self.update_health_index, col)
    
    def create_task_index(self, parent):
        """创建12*1的任务指数"""
        # 任务指数标题
        task_title = tk.Label(
            parent,
            text="任务指数",
            font=('Microsoft YaHei', 12, 'bold'),
            bg='#f8f9fa',
            fg='#2c3e50'
        )
        task_title.pack(pady=2)
        
        # 创建任务指数行
        task_frame = tk.Frame(parent, bg='#f8f9fa')
        task_frame.pack(fill='x', padx=10, pady=2)
        
        # 配置列权重
        for i in range(12):
            task_frame.grid_columnconfigure(i, weight=1)
        
        # 创建12个任务指数数值显示
        self.task_widgets = [None for _ in range(12)]  # 新增：存储任务指数控件
        for col in range(12):
            cell_frame = tk.Frame(task_frame, bg='#f8f9fa', relief='groove', bd=1)
            cell_frame.grid(row=0, column=col, padx=1, pady=1, sticky='ew')
            
            # 任务指数标签
            task_label = tk.Label(
                cell_frame,
                text="T{}".format(col+1),
                font=('Microsoft YaHei', 10),
                bg='#f8f9fa',
                anchor='center'
            )
            task_label.pack(pady=1, fill='x')
            
            # 任务指数数值显示
            task_value = tk.Label(
                cell_frame,
                text="0",
                font=('Microsoft YaHei', 11),
                bg='#ffffff',
                fg='#2c3e50',
                relief='sunken',
                bd=2,
                width=6,
                anchor='center'
            )
            task_value.pack(pady=1)
            self.task_widgets[col] = task_value  # 新增
    
    def create_access_controls(self, parent):
        """创建12*1的接入控件"""
        # 接入控件标题
        access_title = tk.Label(
            parent,
            text="接入状态",
            font=('Microsoft YaHei', 12, 'bold'),
            bg='#f8f9fa',
            fg='#2c3e50'
        )
        access_title.pack(pady=2)
        
        # 创建接入控件行
        access_frame = tk.Frame(parent, bg='#f8f9fa')
        access_frame.pack(fill='x', padx=10, pady=2)
        
        # 配置列权重
        for i in range(12):
            access_frame.grid_columnconfigure(i, weight=1)
        
        # 创建12个接入控件
        self.access_canvas_list = []  # 新增：存储12个接入灯canvas
        for col in range(12):
            cell_frame = tk.Frame(access_frame, bg='#f8f9fa', relief='groove', bd=1)
            cell_frame.grid(row=0, column=col, padx=1, pady=1, sticky='ew')
            
            # 接入标签
            access_label = tk.Label(
                cell_frame,
                text="接入",
                font=('Microsoft YaHei', 10),
                bg='#f8f9fa',
                anchor='center'
            )
            access_label.pack(pady=1, fill='x')
            
            # 接入状态指示灯
            access_canvas = tk.Canvas(
                cell_frame,
                width=25,
                height=25,
                bg='#f8f9fa',
                highlightthickness=0
            )
            access_canvas.pack(pady=1, anchor='center')
            
            # 绘制接入状态指示灯
            self.draw_status_indicator(access_canvas, "unknown")  # 默认全灰
            self.access_canvas_list.append(access_canvas)  # 新增
        
    def draw_connection_indicator(self, connected):
        """绘制连接状态指示灯"""
        self.connection_canvas.delete("all")
        
        if connected:
            # 连接成功 - 绿色
            color = "#28a745"
        else:
            # 未连接 - 灰色
            color = "#6c757d"
        
        # 绘制圆形指示灯
        self.connection_canvas.create_oval(2, 2, 18, 18, fill=color, outline="#495057", width=1)
        
    def toggle_connection(self):
        """切换连接状态"""
        if not self.serial_connected:
            # 尝试连接
            try:
                port = self.serial_combobox.get()
                baudrate = int(self.baudrate_combobox.get())
                print("[DEBUG] 尝试连接串口: {}, 波特率: {}".format(port, baudrate))
                self.serial_port = serial.Serial(port, baudrate, timeout=1)
                self.serial_connected = True
                self.connect_button.config(text="断开")
                self.draw_connection_indicator(True)
                print("[DEBUG] 串口连接成功: {}".format(port))
                self.serial_combobox.config(state='disabled')
                self.baudrate_combobox.config(state='disabled')
                self.refresh_button.config(state='disabled')
                self.save_serial_config()
                self.stop_receive = False
                self.receive_thread = threading.Thread(target=self.receive_data_thread, daemon=True)
                self.receive_thread.start()
                print("[DEBUG] 接收线程已启动")
                # 启用频点下拉菜单
                self.freq_combobox.config(state='readonly')
            except Exception as e:
                print("[ERROR] 连接失败: {}".format(e))
                self.serial_connected = False
                self.draw_connection_indicator(False)
        else:
            # 断开连接
            print("[DEBUG] 断开串口连接")
            self.stop_receive = True
            if self.serial_port:
                self.serial_port.close()
                self.serial_port = None
            self.serial_connected = False
            self.connect_button.config(text="连接")
            self.draw_connection_indicator(False)
            self.serial_combobox.config(state='readonly')
            self.baudrate_combobox.config(state='readonly')
            self.refresh_button.config(state='normal')
            # 禁用频点下拉菜单并重置
            self.freq_combobox.config(state='disabled')
            self.freq_combobox.set("请选择频点")
            # 灯全灰
            for canvas in getattr(self, 'access_canvas_list', []):
                self.draw_status_indicator(canvas, "unknown")
    
    def load_serial_config(self):
        """加载保存的串口配置"""
        try:
            if os.path.exists(self.config_file):
                with open(self.config_file, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    self.saved_serial_port = config.get('serial_port', 'COM1')
                    self.saved_baudrate = config.get('baudrate', '9600')
            else:
                self.saved_serial_port = 'COM1'
                self.saved_baudrate = '9600'
        except Exception as e:
            print("加载配置文件失败: {}".format(e))
            self.saved_serial_port = 'COM1'
            self.saved_baudrate = '9600'
            
    def save_serial_config(self):
        """保存串口配置"""
        try:
            config = {
                'serial_port': self.serial_combobox.get(),
                'baudrate': self.baudrate_combobox.get()
            }
            with open(self.config_file, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print("保存配置文件失败: {}".format(e))
            
    def refresh_serial_ports(self):
        """刷新串口列表"""
        try:
            # 获取系统中实际可用的串口
            available_ports = [port.device for port in serial.tools.list_ports.comports()]
            
            if not available_ports:
                # 如果没有检测到串口，使用默认列表
                available_ports = ["COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "COM10", "COM11", "COM12", "COM13", "COM14", "COM15", "COM16"]
            
            self.serial_combobox['values'] = available_ports
            
            # 如果当前选择的串口不在可用列表中，选择第一个可用串口
            current_port = self.serial_combobox.get()
            if current_port not in available_ports:
                if available_ports:
                    self.serial_combobox.set(available_ports[0])
                else:
                    self.serial_combobox.set("")
                    
        except Exception as e:
            print("刷新串口列表失败: {}".format(e))
            # 出错时使用默认列表
            available_ports = ["COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "COM10", "COM11", "COM12", "COM13", "COM14", "COM15", "COM16"]
            self.serial_combobox['values'] = available_ports
        
    def draw_status_indicator(self, canvas, status):
        """绘制状态指示灯"""
        # 清除画布
        canvas.delete("all")
        
        # 根据状态设置颜色
        if status == "normal":
            color = "#28a745"  # 绿色 - 正常
        elif status == "warning":
            color = "#ffc107"  # 黄色 - 警告
        elif status == "error":
            color = "#dc3545"  # 红色 - 错误
        elif status == "unknown":
            color = "#6c757d" # 灰色 - 未知
        else:
            color = "#6c757d"  # 灰色 - 未知状态
        
        # 绘制圆形指示灯
        canvas.create_oval(5, 5, 20, 20, fill=color, outline="#495057", width=2)
    
    def parse_temperature_text_line(self, line):
        """
        解析MCU文本格式温度数据帧，如: T: 43.4, 60.1, ..., 70.2
        """
        try:
            if not line.startswith('T:'):
                return
            # 去掉头部T:，去除回车换行
            data_str = line[2:].replace('\r','').replace('\n','').strip()
            temps = [float(x) for x in data_str.split(',') if x.strip()]
            print("[DEBUG] Received temps count: {}, first 5: {}".format(len(temps), temps[:5]))
            if len(temps) != 60:
                print("温度数量不对: {}".format(len(temps)))
                return
            for i in range(60):
                col = i // 5
                row = i % 5
                try:
                    temp_val = temps[i]
                    # 温度范围保护
                    if temp_val < -100 or temp_val > 200:
                        print("[WARN] Abnormal temp at {},{}: {}".format(col, row, temp_val))
                        temp_val = 0.0
                    self.temperatures[col][row] = temp_val
                    self.root.after(0, self.update_temperature_display, col, row, temp_val)
                except Exception as e:
                    print("[ERROR] Exception updating temp {}: {}".format(i, e))
        except Exception as e:
            print("解析文本温度数据错误: {}".format(e))
    
    def receive_data_thread(self):
        """串口数据接收线程，支持T:文本温度帧"""
        buffer = b""
        print("[DEBUG] 串口接收线程启动")
        while not self.stop_receive and self.serial_port:
            try:
                if self.serial_port.in_waiting > 0:
                    data = self.serial_port.read(self.serial_port.in_waiting)
                    buffer += data
                    print("[DEBUG] 收到原始数据: {}".format(data))
                    # 按行分割
                    while b'\n' in buffer or b'\r' in buffer:
                        # 支持 \r\n 或 \r 作为行结束
                        if b'\r\n' in buffer:
                            line, buffer = buffer.split(b'\r\n', 1)
                        elif b'\r' in buffer:
                            line, buffer = buffer.split(b'\r', 1)
                        else:
                            break
                        line_str = line.decode(errors='ignore').strip()
                        print("[DEBUG] 解析到行: {}".format(line_str))
                        if line_str.startswith('T:'):
                            print("[DEBUG] 发现温度数据行: {}".format(line_str))
                            self.parse_temperature_text_line(line_str)
            except Exception as e:
                print("[ERROR] 接收数据错误: {}".format(e))
                break
        print("[DEBUG] 接收线程结束")
    
    def update_temperature_display(self, col, row, temp_value):
        """更新温度显示"""
        try:
            print("[DEBUG] update_temperature_display: col={}, row={}, temp={}".format(col, row, temp_value))
            if self.capacitor_widgets and self.capacitor_widgets[col][row]:
                widget = self.capacitor_widgets[col][row]
                
                # 更新温度标签，使用固定格式
                temp_label = widget['temp_label']
                # 统一格式：正数右对齐，负数左对齐，总宽度固定
                if temp_value >= 0:
                    formatted_temp = "{:6.1f}°C".format(temp_value)  # 正数右对齐，6位宽度
                else:
                    formatted_temp = "{:6.1f}°C".format(temp_value)  # 负数也是6位宽度
                temp_label.config(text=formatted_temp)
                
                # 根据温度值更新状态指示灯
                status_canvas = widget['status_canvas']
                if temp_value >= 75:
                    status = "error"  # 红色，不可用
                elif temp_value >= 50:
                    status = "warning"  # 黄色，堪用
                else:
                    status = "normal"  # 绿色，可用
                
                self.draw_status_indicator(status_canvas, status)
                
                # 更新该列的健康指数
                self.root.after(0, self.update_health_index, col)
                
        except Exception as e:
            print("更新温度显示错误: {}".format(e))

    def on_freq_selected(self, event=None):
        """频点选择回调，按加权排序调度列"""
        freq = self.freq_combobox.get()
        if freq == "请选择频点":
            # 灯全灰
            for canvas in getattr(self, 'access_canvas_list', []):
                self.draw_status_indicator(canvas, "unknown")
            return
        # 1. 需要的列数
        freq_map = {"F1（3列）": 3, "F2（4列）": 4, "F3（5列）": 5}
        need_count = freq_map.get(freq, 0)
        # 2. 计算每列加权分数
        candidates = []
        for col in range(12):
            # 健康指数
            health = self.calculate_health_index(col)
            # 任务指数
            task_val = 0
            # 获取任务指数显示控件的值
            if hasattr(self, 'task_widgets') and self.task_widgets[col]:
                try:
                    task_val = float(self.task_widgets[col].cget('text'))
                except Exception:
                    task_val = 0
            else:
                # 若无控件引用，默认0
                task_val = 0
            # 任务裕度
            task_margin = 100 - task_val
            # 可用性判断
            # 只要有温度>=75°C就不可用
            temps = [self.temperatures[col][row] for row in range(5)]
            if any(t >= 75 for t in temps):
                continue
            if task_val >= 100:
                continue
            # 加权分数
            score = 0.7 * health + 0.3 * task_margin
            candidates.append((score, col))
        # 3. 排序，选出前need_count个
        candidates.sort(reverse=True)
        selected = [col for _, col in candidates[:need_count]]
        # 4. 可用列数不足，弹窗
        if len(selected) < need_count:
            messagebox.showwarning("调度失败", "无法调度，请及时检修！")
        # 5. 点亮选中列的接入灯，其余为灰色
        for col, canvas in enumerate(getattr(self, 'access_canvas_list', [])):
            if col in selected:
                self.draw_status_indicator(canvas, "normal")
                # 任务指数加1，最大不超过100
                if hasattr(self, 'task_widgets') and self.task_widgets[col]:
                    try:
                        val = int(float(self.task_widgets[col].cget('text')))
                    except Exception:
                        val = 0
                    val = min(val + 1, 100)
                    self.task_widgets[col].config(text=str(val))
            else:
                self.draw_status_indicator(canvas, "unknown")

def main():
    root = tk.Tk()
    app = CapacitorMonitorGUI(root)
    root.mainloop()

if __name__ == "__main__":
    main() 